package client_commands;

import java.util.StringTokenizer;
import java.util.logging.Logger;

import parameters.RLM_Parameters;
import streaming.Call;
import streaming.CallManager;
import utils.CallSound;
import client.ClientApplication;
import client.ClientBindObject;
import client_gui_chat.ChatDialog;
import client_gui_chat.StreamingPanel;

/**
 * CALL_REQUEST Command.
 * 
 * Parameters:
 * A port_a
 * V port_a port_v
 * 
 * @author UrosKrkic & Radivoje Popovic
 */
public class CALL_REQUESTCommand extends Command {

	
	
	private static Logger log = Logger.getLogger(CALL_REQUESTCommand.class.getCanonicalName());
	
	public CALL_REQUESTCommand(String parameter) {
		setCode(CALL_REQUEST);
		setParameter(parameter);
	}
	
	private ClientApplication theApp;
	private ClientBindObject cbo;
	
	@Override
	public boolean executeCommand(ClientApplication theAppp) {

		this.theApp = theAppp;
	
		try {
			ClientApplication.callRequestSemaphore.acquire();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				// START
				
				StringTokenizer tokens = new StringTokenizer(getParameter());
				
				String username;
				String streamingType;
				int audioPort = 0;
				int videoPort = 0;
				
				boolean audioRequest = false;
				boolean videoRequest = false;
				boolean isAudioAvailable = false;
				boolean isVideoAvailable = false;
				
				try {
					username = tokens.nextToken();
				}
				catch (Exception e) {
//					return false;
					ClientApplication.callRequestSemaphore.release();
					return;
				}
				
				try {
					streamingType = tokens.nextToken();
				}
				catch (Exception e) {
//					return false;
					ClientApplication.callRequestSemaphore.release();
					return;
				}
				
				if ( streamingType.equals("V") ) {
					
					isVideoAvailable = Boolean.parseBoolean(tokens.nextToken());
					
					try {
						videoPort = Integer.parseInt(tokens.nextToken());
						videoRequest = true;
					}
					catch (Exception e) {
						videoRequest = false;
//						return false;
					}
					
					streamingType = tokens.nextToken();
				}
				
				if ( streamingType.equals("A") ) {
					
					isAudioAvailable = Boolean.parseBoolean(tokens.nextToken());
					
					try {
						audioPort = Integer.parseInt(tokens.nextToken());
						audioRequest = true;
					}
					catch (Exception e) {
						audioRequest = false;
					}
				}
				else {
//					return false;
					ClientApplication.callRequestSemaphore.release();
					return;
				}
				
				// end of parsing
				log.info("End of parsing");
				
				//TODO local
//				ClientBindObject cbo = ClientApplication.clientBinding.get(username);
				cbo = ClientApplication.clientBinding.get(username);
				
				if ( cbo == null ) {
					log.info("cbo is null");
//					return false;
					ClientApplication.callRequestSemaphore.release();
					return;
				}
				
				Call call = cbo.getCall();
				
				if (cbo.getDialog() == null) {
					ChatDialog cd = new ChatDialog(theApp.getWindow(), cbo.getUser());
					cbo.setChatDialog(cd);
					cbo.setChatDialogConnection(cbo.getConnection());
					cbo.getDialog().setVisible(true);
				}
				
				
				StringBuffer messageBuffer = new StringBuffer();
				messageBuffer.append("CLIENT_RESPONSE");
				
				if ( call != null ) {
					log.info("call != null");
					// zahtev je prethodno kreiran ka request klijentu
					if ( videoRequest && call.isAudioEstablished() ) {
						log.info("videoRequest && call.isAudioEstablished()");

						CallSound.playCallSound();
						
						int answer = cbo.getDialog().getStreamingPanel().showAcceptPanel(String.format("Do you want to accept video call from: %s ?", username));
						
						if ( answer == StreamingPanel.NO_ANSWER ) {
							cbo.getDialog().getStreamingPanel().showNoVideoPanel();
							cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
							
							messageBuffer.append(" ");
							messageBuffer.append("V ");
							messageBuffer.append(false);
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getVideoPort());
						}
						else if ( answer == StreamingPanel.YES_ANSWER ) {
							
							cbo.getDialog().getStreamingPanel().showNoVideoPanel();
							cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
//							call = CallManager.createCall();
							cbo.getDialog().getStreamingPanel().setVideoComponent(call.getVideoControl().getVideoComponent());
							cbo.getDialog().getStreamingPanel().setMonitorVideoComponent(call.getMonitorVideoControl().getVideoComponent());
							cbo.getDialog().getStreamingPanel().showVideoPanel();
							cbo.getDialog().getStreamingPanel().showMonitorVideoPanel();
							cbo.getDialog().getStreamingPanel().refreshVideo();
//							cbo.setCall(call);
							
							cbo.getDialog().getStreamingPanel().getPeerVolumeSlider().addChangeListener(call.getAudioControl());
							cbo.getDialog().getStreamingPanel().getPeerMute().addChangeListener(call.getAudioControl());
							cbo.getDialog().getStreamingPanel().getMonitorCheckBox().addActionListener(call.getMonitorVideoControl());
							
							
							messageBuffer.append(" ");
							messageBuffer.append("V ");
							messageBuffer.append(call.isVideoAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getVideoPort());
						}
						// ??????????????????
						messageBuffer.append(" ");
						messageBuffer.append("A ");
						messageBuffer.append(call.isAudioAvailable());
						messageBuffer.append(" ");
						messageBuffer.append(RLM_Parameters.getAudioPort());
						
						// TODO pokretanje samo videa
//						boolean flag = call.initializeCall(cbo.getConnection().getClientAddress(), new int[] {audioPort, videoPort});
						boolean flag = false;
						if ( cbo.isConnectionActive() )
							flag = call.initializeVideoCall(cbo.getConnection().getClientAddress(), videoPort, call.getVideoStatus(isVideoAvailable), true);
						call.setVideoEstablished(flag);
						
					}
					else
					if ( videoRequest == call.isVideoRequested() || audioRequest == call.isAudioRequested() ) {
						log.info("videoRequest == call.isVideoRequested() || audioRequest == call.isAudioRequested()");
						messageBuffer.append(" ");
						messageBuffer.append("E");
						
//						boolean flag = call.initializeCall(cbo.getConnection().getClientAddress(), new int[] {audioPort, videoPort});\
						boolean flag = false;
						if (videoRequest &&  cbo.isConnectionActive() )
							flag = call.initializeVideoCall(cbo.getConnection().getClientAddress(), videoPort, call.getVideoStatus(isVideoAvailable), true);
						call.setVideoEstablished(flag);
						flag = false;
						if (audioRequest &&  cbo.isConnectionActive() )
							flag = call.initializeAudioCall(cbo.getConnection().getClientAddress(), audioPort,call.getAudioStatus(isAudioAvailable), false);
						call.setAudioEstablished(flag);
					}
					else {
						log.info("ELSE od videoRequest == call.isVideoRequested() || audioRequest == call.isAudioRequested()");
						if ( audioRequest && call.isVideoRequested() ) {
							log.info("audioRequest && call.isVideoRequested()");
							messageBuffer.append(" ");
							messageBuffer.append("V ");
							messageBuffer.append(call.isVideoAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getVideoPort());
							messageBuffer.append(" ");
							messageBuffer.append("A ");
							messageBuffer.append(call.isAudioAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getAudioPort());
						}
						else if ( videoRequest && call.isAudioRequested() ) {
							log.info("videoRequest && call.isAudioRequested()");

							CallSound.playCallSound();
							
							int answer = cbo.getDialog().getStreamingPanel().showAcceptPanel(String.format("Do you want to accept video call from: %s ?", username));
							
							if ( answer == StreamingPanel.NO_ANSWER ) {
								cbo.getDialog().getStreamingPanel().showNoVideoPanel();
								cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
								messageBuffer.append(" ");
								messageBuffer.append("V ");
								messageBuffer.append(false);
								messageBuffer.append(" ");
								messageBuffer.append(RLM_Parameters.getVideoPort());
							}
							else {
								log.info("PRIHVACENO");
								cbo.getDialog().getStreamingPanel().showNoVideoPanel();
								cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
//								call = CallManager.createCall();
								cbo.getDialog().getStreamingPanel().setVideoComponent(call.getVideoControl().getVideoComponent());
								cbo.getDialog().getStreamingPanel().setMonitorVideoComponent(call.getMonitorVideoControl().getVideoComponent());
								cbo.getDialog().getStreamingPanel().showVideoPanel();
								cbo.getDialog().getStreamingPanel().showMonitorVideoPanel();
								cbo.getDialog().getStreamingPanel().refreshVideo();
//								cbo.setCall(call);
								
								cbo.getDialog().getStreamingPanel().getPeerVolumeSlider().addChangeListener(call.getAudioControl());
								cbo.getDialog().getStreamingPanel().getPeerMute().addChangeListener(call.getAudioControl());
								cbo.getDialog().getStreamingPanel().getMonitorCheckBox().addActionListener(call.getMonitorVideoControl());
								
								messageBuffer.append(" ");
								messageBuffer.append("V ");
								messageBuffer.append(call.isVideoAvailable());
								messageBuffer.append(" ");
								messageBuffer.append(RLM_Parameters.getVideoPort());
							}
							
							messageBuffer.append(" ");
							messageBuffer.append("A ");
							messageBuffer.append(call.isAudioAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getAudioPort());
							
//							boolean flag = call.initializeCall(cbo.getConnection().getClientAddress(), new int[] {audioPort, videoPort});
							boolean flag = false;
							if ( cbo.isConnectionActive() )
								call.initializeVideoCall(cbo.getConnection().getClientAddress(), videoPort, call.getVideoStatus(isVideoAvailable), true);
							call.setVideoEstablished(flag);
						}
						log.info("exit 1");
					}
					log.info("exit 2");
					
					if ( call.isVideoEstablished() || call.isAudioEstablished() ) {
						call.start();
					}
				}
				// bez konflikta
				else {
					log.info("bez konflikta");
					CallSound.playCallSound();

					int answer = cbo.getDialog().getStreamingPanel().showAcceptPanel(String.format("Do you want to accept %s call from %s ?", videoRequest == true ? "video" : "audio", username));
					
					if ( answer == StreamingPanel.NO_ANSWER ) {
						cbo.getDialog().getStreamingPanel().showNoVideoPanel();
						cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
						messageBuffer.append(" ");
						messageBuffer.append("N");
					}
					else {
						log.info("PRIHVACENO");
						cbo.getDialog().getStreamingPanel().showNoVideoPanel();
						cbo.getDialog().getStreamingPanel().showMonitorNoVideoPanel();
						call = CallManager.createCall();
						cbo.getDialog().getStreamingPanel().setVideoComponent(call.getVideoControl().getVideoComponent());
						cbo.getDialog().getStreamingPanel().setMonitorVideoComponent(call.getMonitorVideoControl().getVideoComponent());
						cbo.getDialog().getStreamingPanel().showVideoPanel();
						cbo.getDialog().getStreamingPanel().showMonitorVideoPanel();
						cbo.getDialog().getStreamingPanel().refreshVideo();
						cbo.setCall(call);
						
						cbo.getDialog().getStreamingPanel().getPeerVolumeSlider().addChangeListener(call.getAudioControl());
						cbo.getDialog().getStreamingPanel().getPeerMute().addChangeListener(call.getAudioControl());
						cbo.getDialog().getStreamingPanel().getMonitorCheckBox().addActionListener(call.getMonitorVideoControl());
						
						if ( videoRequest ) {
							log.info("Video request");
							messageBuffer.append(" ");
							messageBuffer.append("V ");
							messageBuffer.append(call.isVideoAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getVideoPort());
						}
						
						if ( audioRequest ) {
							log.info("Audio request");
							messageBuffer.append(" ");
							messageBuffer.append("A ");
							messageBuffer.append(call.isAudioAvailable());
							messageBuffer.append(" ");
							messageBuffer.append(RLM_Parameters.getAudioPort());
						}
						
//						boolean flag = call.initializeCall(cbo.getConnection().getClientAddress(), new int[] {audioPort, videoPort});
						if ( videoRequest ) {
							boolean flag = false;
							if ( cbo.isConnectionActive() )
								flag = call.initializeVideoCall(cbo.getConnection().getClientAddress(), videoPort, call.getVideoStatus(isVideoAvailable), true);
							call.setVideoEstablished(flag);
						}
						if ( audioRequest ) {
							// provera da li je cbo.getConnection() null
							// npr. ako neko uputi call, a zatim se izloguje, a this user pritisne Yes kao odgovor
							boolean flag = false;
							if ( cbo.isConnectionActive() )
								flag = call.initializeAudioCall(cbo.getConnection().getClientAddress(), audioPort, call.getAudioStatus(isAudioAvailable), false);
							call.setAudioEstablished(flag);
						}
						
						if ( call.isVideoEstablished() || call.isAudioEstablished() ) {
							call.start();
						}
					}
				}
				
				if ( cbo.getConnection() != null ) {
					cbo.getConnection().writeData(messageBuffer.toString().trim());
				}
				
				log.info("END");
				
				
//				SwingUtilities.invokeLater(new Runnable() {
//					@Override
//					public void run() {
//						SwingUtilities.updateComponentTreeUI(cbo.getDialog());
//					}
//				});
				
				// END
			}
		}).start();
		
		
		ClientApplication.callRequestSemaphore.release();
		
		return true;
	}

}
